package com.hl.card.pay.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hl.card.common.persistence.model.User;
import com.hl.card.common.util.AmountUtil;
import com.hl.card.common.util.CurrencyUtil;
import com.hl.card.common.util.ResponseModel;
import com.hl.card.common.util.ResponseObject;
import com.hl.card.modular.pack.service.UserDataService;
import com.hl.card.modular.system.service.ISysDicService;
import com.hl.card.pay.dto.MerchantDto;
import com.hl.card.pay.dto.PayDto;
import com.hl.card.pay.service.PayService;
import com.hl.card.pay.util.HttpTool;
import com.hl.card.pay.util.PayDigestUtil;
import com.hl.card.pay.vo.Coin;
import com.hl.card.pay.vo.PayVo;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.*;
@Service
public class PayServiceImpl implements PayService {
    private Logger logger= LoggerFactory.getLogger(this.getClass());
    @Value("${pay.config.cardUrl}")
    private String cardUrl;
    @Value("${pay.config.createOrder}")
    private String createOrder;
    @Value("${pay.config.mchInfo}")
    private String mchInfo;
    @Value("${pay.config.payChanel}")
    private String payChanel;
    @Value("${pay.config.reqKey}")
    private String reqKey;
    @Value("${pay.config.doPay}")
    private String doPay;
    @Value("${pay.config.quryPayOrder}")
    private String quryPayOrder;
    @Value("${pay.config.cardBlance}")
    private String cardBlance;
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private UserDataService userDataService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    ISysDicService sysDicService;
    @Override
    public MerchantDto getMerchantById(String mchId) {
        String url=mchInfo+"?mchId="+mchId;
        logger.info("根据商户id获取商户信息："+url);
        ResponseObject json = restTemplate.getForEntity(url,ResponseObject.class).getBody();
        Map map= (Map) json.getData();
        JSON jo = (JSON) JSON.toJSON(map);
        MerchantDto merchantDto=  JSONObject.toJavaObject(jo,MerchantDto.class);
        logger.info(jo.toJSONString());
        return merchantDto;
    }
    @Override
    public List<Map> getPayChanelByMchId(String mchId) {
        String url=payChanel+"?mchId="+mchId;
        ResponseObject json = restTemplate.getForEntity(url,ResponseObject.class).getBody();
        List<Map> list= (List<Map>) JSONArray.parse(json.getData().toString());
        List<Map> list2=new ArrayList<>();
        for(Map map:list){
            if(map.get("id").equals(57)){
                list2.add(map);
            }
        }
        return list;
    }
    @Override
    public Object pay(PayDto payDto) {
        //调用支付接口
        String payUrl=cardUrl+doPay;
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("mchId", payDto.getMchId());                               // 商户ID
        jsonObject.put("mchOrderNo", payDto.getMchOrderNo());     // 商户订单号
        String reqSign=PayDigestUtil.getSign(jsonObject, reqKey);//请求参数签名
        jsonObject.put("sign",reqSign);
        JSONObject paramsMap=new JSONObject();
        paramsMap.put("params", jsonObject.toJSONString());
        JSONObject res = HttpTool.postJSONObject(payUrl, paramsMap, restTemplate);
        return res.toJSONString();
    }

    @Override
    public Object quryPayOrder(PayDto payDto) {
        //调用支付接口
        String payUrl=cardUrl+quryPayOrder;
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("mchId", payDto.getMchId());                               // 商户ID
        jsonObject.put("mchOrderNo", payDto.getMchOrderNo());     // 商户订单号
        jsonObject.put("executeNotify", "true");
        reqKey=getMerchantById(payDto.getMchId()).getReqKey();
        String reqSign=PayDigestUtil.getSign(jsonObject, reqKey);//请求参数签名
        jsonObject.put("sign",reqSign);
        JSONObject paramsMap=new JSONObject();
        paramsMap.put("params", jsonObject.toJSONString());
        JSONObject res = HttpTool.postJSONObject(payUrl, paramsMap, restTemplate);
        return res.toJSONString();
    }

    @Override
    public ResponseModel checkUser(String userId, String payPassword) {
        ResponseModel responseModel=new ResponseModel();
        responseModel.setStatus("0001");
        responseModel.setData("密码正确");
        if(StringUtils.isEmpty(userId)){
            responseModel.setStatus("0000");
            responseModel.setData("用户信息错误");
            return  responseModel;
        }
       User user=userDataService.selectUser(userId);
        if(user==null){
            responseModel.setStatus("0000");
            responseModel.setData("用户信息错误");
            return  responseModel;
        }else if(!user.getUserPayPassword().equals(payPassword)){
            responseModel.setStatus("0000");
            responseModel.setData("密码错误");
            return  responseModel;
        }
        return  responseModel;
    }
    /**
     * 生成订单
     * @param payVo
     * @return
     */
    @Override
    public ResponseModel creteOrder(PayVo payVo) {
        System.out.println("客户端IP："+payVo.getClientIp());
        PayDto   payDto=new PayDto();
        BeanUtils.copyProperties(payVo,payDto);
        JSONObject  paramMap= (JSONObject) JSON.toJSON(payDto);
        reqKey=getMerchantById(payVo.getMchId()).getReqKey();
        String reqSign = PayDigestUtil.getSign(paramMap, reqKey);//请求参数签名
        payDto.setSign(reqSign);
        String url = cardUrl+createOrder;
        JSONObject postData =(JSONObject) JSON.toJSON(payDto);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
        System.out.println(postData.toJSONString());
        map.add("params",postData.toJSONString());
        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
        String str = restTemplate.postForEntity(url, request, String.class).getBody();
        System.out.println(str);
        JSONObject jsonObject=JSONObject.parseObject(str);
        ResponseModel responseModel=new ResponseModel();
        if(jsonObject.get("resCode").equals("SUCCESS")){
            responseModel.setStatus("0000");
            responseModel.setData(jsonObject);
        }else{
            responseModel.setStatus("0001");
        }
        return responseModel;
    }
    
    @Override
    public String getBlance(PayVo payVo) {
        String cardInfoUrl=cardUrl+cardBlance;
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("userId",payVo.getUserId());
        jsonObject.put("cardType",payVo.getCurrency());
        JSONObject res = HttpTool.postJSONObject(cardInfoUrl, jsonObject, restTemplate);
        JSONObject obj= (JSONObject) res.get("obj");
        String  remainPart="0";
        if( obj!=null ){
            BigDecimal bigDecimal=new BigDecimal(obj.get("remainPart").toString());
            if(payVo.getCurrency().equals("htl")){
                bigDecimal=bigDecimal.setScale(0,BigDecimal.ROUND_DOWN);
            }else if(payVo.getCurrency().equals("eth")){
                bigDecimal=bigDecimal.setScale(4,BigDecimal.ROUND_DOWN);
            }
            remainPart= bigDecimal.toString();
        }
        return remainPart;
    }
    @Override
    public String getBlance(String userId, String currency) {
        PayVo payVo=new PayVo();
        payVo.setUserId(userId);
        payVo.setCurrency(currency);
       return getBlance(payVo);
    }
    @Override
    public String payNotify(PayVo payVo,ResponseModel responseModel) {
        String redirectUrl=payVo.getRedirectUrl();
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("mchOrderNo",payVo.getMchOrderNo());
        jsonObject.put("userId",payVo.getUserId());
        jsonObject.put("payOrderId","");
        jsonObject.put("amount",payVo.getAmount());
        jsonObject.put("status",responseModel.getStatus());
        logger.info("返回参数:"+jsonObject.toJSONString());
        try {
            if(redirectUrl.startsWith("http")||redirectUrl.startsWith("https")){
            }else{
                redirectUrl="http://"+redirectUrl;
            }
            JSONObject res = HttpTool.postJSONObject(redirectUrl, jsonObject, restTemplate);
            logger.info(res.toJSONString());
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    @Override
    public List<Map> getPayList() {
        List list=new ArrayList();
        Map map1=new HashMap();
        map1.put("name","微信支付");
        map1.put("icon","https://hlbibi.oss-cn-shenzhen.aliyuncs.com/pay/weixin.png");
        map1.put("channelId","1");
        Map map2=new HashMap();
        map2.put("name","支付宝支付");
        map2.put("icon","https://hlbibi.oss-cn-shenzhen.aliyuncs.com/pay/zhifubao.png");
        map1.put("channelId","2");
        list.add(map1);
        list.add(map2);
        return list;
    }
    @Override
    public List<Map> getPayChanelSimple(String asyn,String userId,String htl,String eth) {
        List<Map> list= new ArrayList<>();
        Map mapHtl=new HashMap();
        Map mapEth=new HashMap();
        PayVo p1=new PayVo();
        p1.setUserId(userId);
        p1.setCurrency("htl");
        String blance1 = getBlance(p1);
        PayVo p2=new PayVo();
        p2.setUserId(userId);
        p2.setCurrency("eth");
        String blance2 = getBlance(p2);
        mapHtl.put("unit","HTL");
        mapHtl.put("remainPart",blance1);
        mapHtl.put("amount",htl);
        mapEth.put("unit","ETH");
        mapEth.put("remainPart",blance2);
        mapEth.put("amount",eth);
        mapEth.put("rate",getEthReal());
        if(asyn==null){
            asyn="0";
        }
        if(asyn.equals("0")){
            mapHtl.put("channelId","HL_HTL_PAY");
            mapHtl.put("remark","HTL即时支付");
            mapEth.put("channelId","HL_ETH_PAY");
            mapEth.put("remark","ETH即时支付");
        }else if(asyn.equals("1")){
            mapHtl.put("channelId","HL_HTL_ASYN_PAY");
            mapHtl.put("remark","航旅HTL支付");
            mapEth.put("channelId","HL_ETH_ASYN_PAY");
            mapEth.put("remark","航旅ETH支付");
        }
        list.add(mapHtl);
        list.add(mapEth);
        return list;
    }

    @Override
    public String getEthReal() {
        List<Map<String, Object>> list = sysDicService.selectListByCode("ETHPZ");
        Double rate = 1.0;
        if(list != null) {
            String value = (String) list.get(0).get("dicValue");
            if(org.apache.commons.lang.StringUtils.isNotBlank(value)) {
                try {
                    rate = Double.parseDouble(value);
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
            }
        }
        String  price="0";
        Optional<JSONObject> jso = null;
        try {
            String resp = restTemplate.getForObject("https://api.feixiaohao.com/site/headercoinlist#", String.class);
            JSONObject jo = JSON.parseObject(resp);
            List<JSONObject> ja=JSONArray.parseArray(jo.get("content").toString(),JSONObject.class);
            jso = ja.stream().filter(coin -> coin.get("CoinCode").equals("ethereum")).findFirst();
        }catch (Exception e){
            logger.info("eth 汇率获取失败");
            logger.info(e.getMessage());
        }
        ListOperations<String, String> vo = redisTemplate.opsForList();
        String	hisPriceStr=vo.index("ethPrice", 0);
        if(hisPriceStr==null){
            hisPriceStr="0";
        }
        Double hisPrice=Double.parseDouble(hisPriceStr);
        if(jso!=null&&jso.isPresent()){
            price=jso.get().get("Price_Cny").toString();
            Double dPrice=Double.parseDouble(price);
            Double	ratePrice=dPrice*(1-rate);
            if(ratePrice>(hisPrice*1.01)||dPrice<hisPrice){
                vo.leftPush("ethPrice", ratePrice.intValue()+"");
                price=dPrice.toString();
            }else{
                price=hisPriceStr;
            }
         }
        if(!price.equals("0")){
            vo.leftPush("ethPrice", new Double(price).intValue()+"");
        }else{
            price=vo.index("ethPrice", 0);
        }
        return new Double(price).intValue()+"";
    }
    @Override
    public String getGusdRealHQZ() {
        String resp = restTemplate.getForObject("https://mn.hqz.com/v2/index/coinbase?coincode=gemini-dollar", String.class);
        JSONObject jo = JSON.parseObject(resp);
        JSONObject jso= JSONObject.parseObject(jo.get("data").toString());
        return  jso.get("cny_rate").toString();
    }
    @Override
    public String getGusdReal() {
        String real="0";
        String price="0";
        try {
            Document doc = Jsoup.connect("https://www.feixiaohao.com/currencies/geminidollar/").get();
            logger.info(doc.title());
            Elements newsHeadlines = doc.select(".mainPrice .convert");
            for (Element headline : newsHeadlines) {
                logger.info(headline.text());
                real=headline.text();
            }
        } catch (IOException e) {
            logger.info("GUSD 汇率获取失败");
            logger.info(e.getMessage());
            e.printStackTrace();
        }
        ListOperations<String, String> vo = redisTemplate.opsForList();
        String	hisPriceStr=vo.index("gusdPrice", 0);
        if(hisPriceStr==null){
            hisPriceStr="0";
        }
        if(!real.equals("0")){
            vo.leftPush("gusdPrice", real);
            price=real;
        }else{
            price=hisPriceStr;
        }
        return price;
    }

    @Override
    public String getGusdRate() {
    String rateStr=getGusdReal();
    BigDecimal rate=new BigDecimal(rateStr).setScale(2,BigDecimal.ROUND_HALF_DOWN);
    return rate.toString();
    }
    @Override
    public Map<String, Object> getGusdAmount(String cnyAmount) {
        Map map=new HashMap();
        String price=getGusdReal();
        BigDecimal bPrice=new BigDecimal(price).setScale(2,BigDecimal.ROUND_DOWN);
        BigDecimal b=new BigDecimal(cnyAmount);
        BigDecimal result = b.divide(bPrice,2,BigDecimal.ROUND_UP);
        String echo=result.toString();
        map.put("echo",echo);
        map.put("param",AmountUtil.convertDollar2Cent(echo));
        return  map;
    }
    @Override
    public Map<String,Object> getEthAmount(String cnyAmount) {
        Map map=new HashMap();
        String price=getEthReal();
        Double dPrice=Double.parseDouble(price);
        Double d=Double.parseDouble(cnyAmount);
        Double result=d/dPrice;
        if(result>0.0009){
            result=Math.ceil(result*10000)/10000;
        }else{
            result=0.0;
        }
        NumberFormat nf = NumberFormat.getNumberInstance();
        nf.setMinimumFractionDigits(4);
        String echo = nf.format(result);
        map.put("echo",echo);
        String  re = CurrencyUtil.converEthToGWEIToStr(result);
        map.put("param",re.replace(".",",").split(",")[0]);
        return map;
    }
    @Override
    public String findChannelId(String asyn, String channel) {
        if(asyn.equals("0")){
            if(channel.equals("htl")){
                return "HL_HTL_PAY";
            }
            if(channel.equals("eth")){
                return "HL_ETH_PAY";
            }
            if(channel.equals("gusd")){
                return "HL_GUSD_PAY";
            }
        }
        if(asyn.equals("1")){
            if(channel.equals("htl")){
                return "HL_HTL_ASYN_PAY";
            }
            if(channel.equals("eth")){
                return "HL_ETH_ASYN_PAY";
            }
            if(channel.equals("gusd")){
                return "HL_GUSD_ASYN_PAY";
            }
        }
        return null;
    }

    @Override
    public PayVo wrapPayVo(PayVo payVo) {
        logger.info("wrapPayVo"+JSONObject.toJSONString(payVo));
        if(payVo.getCoins()==null){
            payVo.setCoins(new ArrayList<>());
        }
        List<Coin> coins=payVo.getCoins();
        coins.stream().forEach(coin -> {
            coin.setChannelId(findChannelId(payVo.getAsyn(),coin.getCurrency()));
            coin.setUnit(coin.getCurrency().toUpperCase());
            String remark=coin.getUnit()+"支付";
            coin.setRemark(remark);
            coin.setRemainPart(getBlance(payVo.getUserId(),coin.getCurrency()));
            coin.setEchoAmount(coin.getAmount());
            if(coin.getCurrency().equals("eth")){
                if(coin.getAmount().equals("0")){
                    Map<String,Object> map=getEthAmount(payVo.getCnyAmount());
                    coin.setAmount(map.get("param").toString());
                    coin.setEchoAmount(map.get("echo").toString());
                }else{
                    coin.setEchoAmount(coin.getAmount());
                    coin.setAmount(CurrencyUtil.converEthToGWEI(Double.parseDouble(coin.getAmount())).toString());
                }
                coin.setRate(getEthReal());
            }else if(coin.getCurrency().equals("gusd")){
                if(coin.getAmount().equals("0")){
                    Map<String,Object> map=getGusdAmount(payVo.getCnyAmount());
                    coin.setAmount(map.get("param").toString());
                    coin.setEchoAmount(map.get("echo").toString());
                }else{
                    coin.setEchoAmount(coin.getAmount());
                    coin.setAmount(AmountUtil.convertDollar2Cent(coin.getAmount()));
                }
                coin.setRate(getGusdRate());
            }
        });
        payVo.setCoins(coins);
        return payVo;
    }
    @Override
    public String findCurrencyByChannelId(String channelId) {
        String currency="cny";
        if(channelId.contains("HTL")){
            currency="htl";
        }
        if(channelId.contains("ETH")){
            currency="eth";
        }
        if(channelId.contains("GUSD")){
            currency="gusd";
        }
        return currency;
    }
}